from motor.motor_asyncio import AsyncIOMotorClient
from typing import Optional, List, Dict
import logging

logging.basicConfig(level=logging.INFO)


class MongoDBManager:
    def __init__(self):
        self.client = None
        self.database = None
        self.connection_string = None
        self.database_name = None

    def init_config(self, connection_string: str, database_name: str):
        self.client: Optional[AsyncIOMotorClient] = None
        self.database = None
        self.connection_string = connection_string
        self.database_name = database_name
        
    async def connect(self):
        """连接到 MongoDB"""
        try:
            # 连接配置选项
            self.client = AsyncIOMotorClient(
                self.connection_string,
                maxPoolSize=100,  # 最大连接数
                minPoolSize=10,   # 最小连接数
                maxIdleTimeMS=30000,  # 最大空闲时间
                serverSelectionTimeoutMS=5000,  # 服务器选择超时
                connectTimeoutMS=10000,  # 连接超时
                socketTimeoutMS=30000,   # socket 超时
            )
            
            # 测试连接
            await self.client.admin.command('ping')
            self.database = self.client[self.database_name]
            
            logging.info("成功连接到 MongoDB")
            return True
            
        except Exception as e:
            logging.error(f"连接 MongoDB 失败: {e}")
            return False
    
    async def close(self):
        """关闭连接"""
        if self.client:
            self.client.close()
            logging.info("MongoDB 连接已关闭")
    
    async def insert_one(self, collection_name: str, document: Dict) -> str:
        """插入单个文档"""
        try:
            result = await self.database[collection_name].insert_one(document)
            return str(result.inserted_id)
        except Exception as e:
            logging.error(f"插入文档失败: {e}")
            raise
    
    async def insert_many(self, collection_name: str, documents: List[Dict]) -> List[str]:
        """插入多个文档"""
        try:
            result = await self.database[collection_name].insert_many(documents)
            return [str(id) for id in result.inserted_ids]
        except Exception as e:
            logging.error(f"批量插入文档失败: {e}")
            raise
    
    async def find_one(self, collection_name: str, query: Dict) -> Optional[Dict]:
        """查询单个文档"""
        try:
            document = await self.database[collection_name].find_one(query)
            return document
        except Exception as e:
            logging.error(f"查询文档失败: {e}")
            raise
    
    async def find_many(self, collection_name: str, query: Dict = None, 
                       limit: int = 100, skip: int = 0, 
                       sort: List[tuple] = None) -> List[Dict]:
        """查询多个文档"""
        try:
            query = query or {}
            cursor = self.database[collection_name].find(query)
            
            if sort:
                cursor = cursor.sort(sort)
            
            if skip:
                cursor = cursor.skip(skip)
            
            if limit:
                cursor = cursor.limit(limit)
            
            documents = await cursor.to_list(length=limit)
            return documents
        except Exception as e:
            logging.error(f"查询多个文档失败: {e}")
            raise
    
    async def update_one(self, collection_name: str, query: Dict, update: Dict) -> bool:
        """更新单个文档"""
        try:
            result = await self.database[collection_name].update_one(query, update)
            return result.modified_count > 0
        except Exception as e:
            logging.error(f"更新文档失败: {e}")
            raise
    
    async def update_many(self, collection_name: str, query: Dict, update: Dict) -> int:
        """更新多个文档"""
        try:
            result = await self.database[collection_name].update_many(query, update)
            return result.modified_count
        except Exception as e:
            logging.error(f"批量更新文档失败: {e}")
            raise
    
    async def delete_one(self, collection_name: str, query: Dict) -> bool:
        """删除单个文档"""
        try:
            result = await self.database[collection_name].delete_one(query)
            return result.deleted_count > 0
        except Exception as e:
            logging.error(f"删除文档失败: {e}")
            raise
    
    async def delete_many(self, collection_name: str, query: Dict) -> int:
        """删除多个文档"""
        try:
            result = await self.database[collection_name].delete_many(query)
            return result.deleted_count
        except Exception as e:
            logging.error(f"批量删除文档失败: {e}")
            raise
    
    async def count_documents(self, collection_name: str, query: Dict = None) -> int:
        """统计文档数量"""
        try:
            query = query or {}
            count = await self.database[collection_name].count_documents(query)
            return count
        except Exception as e:
            logging.error(f"统计文档失败: {e}")
            raise


mongo_manager = MongoDBManager()


if __name__ == '__main__':
    import asyncio

    async def main_demo():
        """主演示函数"""
        # 创建 MongoDB 管理器实例
        mongo_manager.init_config(
            connection_string="mongodb://admin:MY.io2019@localhost:27017",
            database_name="admin"
        )
        
        if not await mongo_manager.connect():
            logging.error("无法连接到 MongoDB，退出演示")
            return
            
        final_count = await mongo_manager.count_documents("system.users")
        logging.info(f"演示结束，用户集合中剩余 {final_count} 个文档")

        await mongo_manager.close()

    def run_with_event_loop():
        """使用 asyncio event loop 运行演示"""
        # 获取事件循环
        loop = asyncio.get_event_loop()
        
        try:
            logging.info("开始 MongoDB 演示...")
            
            # 运行主演示函数
            loop.run_until_complete(main_demo())
            
            logging.info("MongoDB 演示完成!")
            
        except KeyboardInterrupt:
            logging.info("用户中断演示")
        except Exception as e:
            logging.error(f"运行演示时发生错误: {e}")
        finally:
            # 关闭事件循环
            if not loop.is_closed():
                loop.close()


    run_with_event_loop()
